package se.webbzon.oschi01.world;

import java.awt.geom.Point2D;
import java.util.Observable;
import java.util.Observer;

import se.webbzon.oschi01.nbt.NBTException;
import se.webbzon.oschi01.nbt.Tag;
import se.webbzon.oschi01.nbt.Tags;
import se.webbzon.oschi01.utils.ObjectUtils;

public class Chunks {
	
	public static final ObservableChunk observableChunk(final Chunk chunk) {
		if (chunk instanceof ObservableChunk)
			return (ObservableChunk) chunk;
		
		final CoordinateMediator mediator = new CoordinateMediator();
		if (chunk.isLoaded()) try {
			mediator.attachTo(chunk.getRoot());
		} catch (NBTException e) {
			throw new IllegalArgumentException(e);
		}
		
		final ObservableChunk oc = new ObservableChunk() {

			@Override public Point2D getCoordinate() {
				return chunk.getCoordinate();
			}
			
			@Override public void setCoordinate(int x, int z) {
				chunk.setCoordinate(x, z);
				setChanged();
				notifyObservers(new ChunkEvent(this,Action.MOVED,chunk.getCoordinate()));
			}

			@Override public long getTimestamp() {
				return chunk.getTimestamp();
			}
			
			@Override public void setTimestamp(long timestamp) {
				chunk.setTimestamp(timestamp);
				setChanged();
				notifyObservers(new ChunkEvent(this,Action.TIMESTAMP_CHANGED,timestamp));
			}

			@Override public Tag<?> getRoot() throws NBTException {
				Tag<?> root = chunk.getRoot();
				if (mediator.getRoot() == null)
					mediator.attachTo(root);
				return root;
			}
			
			@Override public boolean equals(Object o) {
				return ObjectUtils.equals(Chunk.class, chunk, o);
			}

			@Override public boolean isLoaded() {
				return chunk.isLoaded();
			}

			@Override public void free() {
				chunk.free();
				setChanged();
				notifyObservers(new ChunkEvent(this,Action.FREED,null));
			}

		};
		
		mediator.addObserver(new Observer() {

			@Override public void update(Observable o, Object arg) {
				Point2D p = oc.getCoordinate();
				int x = (int) p.getX();
				int z = (int) p.getY();
				oc.setCoordinate(x,z);
			}
			
		});

		return oc;
	}
	
	public static final Chunk unmodifiableChunk(final Chunk chunk) {
		return new Chunk() {

			@Override public Point2D getCoordinate() {
				return chunk.getCoordinate();
			}
			
			@Override public void setCoordinate(int x, int z) {
				throw new UnsupportedOperationException();
			}

			@Override public long getTimestamp() {
				return chunk.getTimestamp();
			}
			
			@Override public void setTimestamp(long timestamp) {
				throw new UnsupportedOperationException();
			}
			
			@Override public Tag<?> getRoot() throws NBTException {
				return Tags.unmodifiableTag(chunk.getRoot());
			}
			
			@Override public boolean equals(Object o) {
				return ObjectUtils.equals(Chunk.class, chunk, o);
			}

			@Override public boolean isLoaded() {
				return chunk.isLoaded();
			}

			@Override public void free() {
				chunk.free();
			}
			
		};
		
	}

}
